package com.amap.demo;

import java.io.*;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.security.GeneralSecurityException;
import java.security.KeyFactory;
import java.security.PrivateKey;
import java.security.Signature;
import java.security.spec.PKCS8EncodedKeySpec;
import java.util.*;

/**
 * @author liuyi
 * @since 2025/10/31 16:07
 */
public class GenerateSignUtils {

    /**
     * 使用商家私钥生成签名
     *
     * @param paramMap
     * @return
     * @throws Exception
     */
    public static String generateSign(Map<String, String> paramMap) throws Exception {
        //使用商家私钥进行加签，请在高德云店「接入准备及配置」页面生成并获取商家私钥
        String merchantPrivateKey = "MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCJujqRA/s7dESFWKOp/R458vJ8DW+LhfpqQtANAjdHDkWqaK6iUMGQ4Z7CeYZCI7wO5Dpj+ZDlS23woaRDTQ1KooynlTpeun3pTrSmfXtszxsPQ25c01sJ8lpbg0NJgyTQ9yCnMj0XJtIu/zTIIXpx6xBuRxSL6xiDigA2Nfjgz/YXmhrxe7+hZbgG7/lD2gnvG83RS5t8a7AT579Djgx3lE3FojJhASwmIsDIdaO89vZhfzIw6I/NHMvVNIy35NVZKrGsUBn3monAUuirS8lbcAErBkiWYGz5vtDBYCrD1PsohmqHxsyZS/P9Rj+zOXMQnqIRoj1IjvIyUGh8irfVAgMBAAECggEALZCxI5z/lzHmIX+r1edqAp3/307KooxWxqUIE+WxyA5OugwcCpNRFs+uKITwCB2ub/bN4pmEeHe2DbBMmf958EFK636Raxmj4nYpihNlrB/wweH7NzatneLSRghtUHrUyVWZNfeHAovTab0BB10cF2g/bVySzZ+f4pTbcRP2HNnzBbhqAMlwIjT5T0zkDZDFoql5ZdB0wzAtO1RiEa9irUz/eVGun3lvePl74QpAi2UNP03jpjRrQkApOuTH1wdW+e3wM2puSk6OeCdVnC22uIKSfhXha2oMBIoLaoyYbTVeGdzNJjvzcYpmj/I5It9gyzDY/JD7EnwWWqmCcy0BWQKBgQDYGE5qfyZqKufoVZc5dtilMSe4YmjkNlukibdq7RVApXeZ3upQi1oCept0cfzStikbxbbY3hJcZq/Jyg6LVsKWND8BcRddEIBX9LWFhe6+Ti+qU3X0L2ZNlPkDjZMLHRdBkSM5be+sKHBUKpVoWCzgmjXXpn32q4THn8dgHhSegwKBgQCjKSuHuMfZ5QoVomWINTpoRGYXeOxeBElT7DcdIJdNH4vkZpkvQF09VfCbWB+VeeFT9PustCZCPtT2lAn9jmNTsnPYdCXNirzc0tfPrpGxIHU5DpSD5gDb/gDoeDYHhSQHese6f7jVbMxSOR6KE9i+QoiSuEoJ+pW9NPRSZBaAxwKBgQC0mXvP3XxJdppivkWorP7a8H31x6lKMXPdy4sTPhlo8eFHI9pIfm43bCjH5QwbPkqU/2SVUuOdfeSkjM4i/dualQejONUB3mylFcsvUIP7YHTNsPr/nS2u4TZMFeIyg5mQHrCFqq+H/jQC46QClM7M15TwKiFUKnzKKWsDlaA96QKBgGkZ1BiRRuttRpm5Cn47C2yu4rSsCFZnnHSa7MWugMgFUi/Gh1aQt38TJPJsSawX3rYeUSBmy15Q6w4LPoQ+fG0lvsnnx5InlJEKoEn/wYm/xsMCSVjNiDAt5pfZF7SwZw0KYi4YqA+TDerJMIrxTeUBJsicPdU/vcUrn1aTcotxAoGBAJC0bD+4k1Kthw616e0A+3UZv9AfG5uDkPFUI+0yKb0/9v+hA/60syWYvyMk6xFk5oxZWq4c/mkVhCHII8F28UZ3NnFljqXC1UVjryCqkRHnnoejs+qLx2jx/axUpDS9sqGHJIT62WLx9QUtwX4hZf4yySANPkfoeSJzPM+XJRdz";
        String signContent = getSignContent(paramMap);
        return getSign(signContent, merchantPrivateKey);
    }

    /**
     * 参数转换为待加签字符串
     *
     * @param paramMap 待生成加密sign的参数集合
     */
    // 修复 GenerateSignUtils 中的 getSignContent 方法
    private static String getSignContent(Map<String, String> paramMap) throws UnsupportedEncodingException {
        StringBuilder content = new StringBuilder();
        List<String> keys = new ArrayList<>(paramMap.keySet());
        Collections.sort(keys); // 按key升序，与CheckSignUtils一致
        for (int i = 0; i < keys.size(); i++) {
            String key = keys.get(i);
            // 排除不参与签名的参数（与CheckSignUtils一致）
            if ("sign_type".equals(key) || "sign".equals(key) || "need_encrypt".equals(key)) {
                continue;
            }
            String value = paramMap.get(key);
            // 非空参数拼接，且对value做URL编码（新增，与CheckSignUtils对齐）
            if (key != null && !key.isEmpty() && value != null && !value.isEmpty()) {
                String encodedValue = URLEncoder.encode(value, StandardCharsets.UTF_8.name());
                if (i > 0) {
                    content.append("&");
                }
                content.append(key).append("=").append(encodedValue);
            }
        }
        return content.toString();
    }

    /**
     * 字符串加签
     *
     * @param signContent        待加密的参数字符串
     * @param merchantPrivateKey 商家应用私钥
     * @throws IOException
     * @throws GeneralSecurityException
     */
    private static String getSign(String signContent, String merchantPrivateKey) throws IOException, GeneralSecurityException {
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        byte[] encodedKey = readText(new ByteArrayInputStream(merchantPrivateKey.getBytes())).getBytes();
        encodedKey = Base64.getDecoder().decode(encodedKey);
        PrivateKey priKey = keyFactory.generatePrivate(new PKCS8EncodedKeySpec(encodedKey));
        Signature signature = Signature.getInstance("SHA256WithRSA");
        signature.initSign(priKey);
        signature.update(signContent.getBytes("UTF-8"));
        byte[] signed = signature.sign();
        return new String(Base64.getEncoder().encode(signed));
    }

    private static String readText(InputStream in) throws IOException {
        Reader reader = new InputStreamReader(in);
        StringWriter writer = new StringWriter();

        int bufferSize = 4096;
        char[] buffer = new char[bufferSize];
        int amount;
        while ((amount = reader.read(buffer)) >= 0) {
            writer.write(buffer, 0, amount);
        }
        return writer.toString();
    }
}
